package com.java.practise.tags;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

@SuppressWarnings("serial")
public class Pagination extends TagSupport {
	private static final String BREAD_CRUMB_LITERAL = "&p=";
	private static final String BREAD_CRUMB_LITERAL_2 = "p=";
	
	private ResultSet rst = null;
	private boolean select = false;
	private boolean rowCountRequired = false;
	private int currentPage = 0;
	private boolean pageLinksRequired = false;
	private int rowsPerPage = 10;
	private boolean paginated = false;
	private String servletPath = "";
	private String queryString = "";
	
	public void setRst(ResultSet rst) {
		this.rst = rst;
	}

	public void setSelect(boolean flag) {
		this.select = flag;
	}	
	
	public void setRowCountRequired(boolean rowCountRequired) {
		this.rowCountRequired = rowCountRequired;
	}
	
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public void setPageLinksRequired(boolean pageLinksRequired) {
		this.pageLinksRequired = pageLinksRequired;
	}

	public void setRowsPerPage(int rowsPerPage) {
		this.rowsPerPage = rowsPerPage;
	}
	
	public void setPaginated(boolean paginated) {
		this.paginated = paginated;
	}
	
	public void setServletPath(String servletPath) {
		this.servletPath = servletPath;
	}

	public void setQueryString(String queryString) {
		if(queryString != null && queryString.length() > 0) {
			int endIndex = queryString.indexOf(BREAD_CRUMB_LITERAL);
			if(endIndex >= 0) {
				this.queryString = queryString.substring(0, endIndex);
			}
			else {
				endIndex = queryString.indexOf(BREAD_CRUMB_LITERAL_2);
				if(endIndex >= 0) {
					this.queryString = queryString.substring(0, endIndex);
				}
				else {
					this.queryString = queryString;
				}
			}
		}
		else {
			this.queryString = "";
		}
	}

	public int doEndTag() throws JspException {
		try {
			JspWriter out = pageContext.getOut();
			out.print(paginatedTable());
		}
		catch(Exception ex) {
			throw new JspException("Exception occured: " + ex.getMessage());
		}
		return EVAL_PAGE;
	}
	
	public StringBuffer paginatedTable() throws SQLException{
		StringBuffer stringBuffer = new StringBuffer();
		ResultSetMetaData rsmd = rst.getMetaData();
		if(paginated) {
			try {
				int z = 1;
				int page = 0;
				int totalNoOfRows = getRowCount(rst);
				int totalNoOfPages = totalNoOfRows / rowsPerPage ;
				if(currentPage>0) {
					page = currentPage - 1;
				}
				int absoluteRowPosition = (rowsPerPage * page);
				if(absoluteRowPosition > 0) {
					rst.absolute(absoluteRowPosition);
				}
				if(totalNoOfRows%rowsPerPage > 0) {
					totalNoOfPages++;
				}
			    int count = rsmd.getColumnCount(); 
			    stringBuffer.append("<tr>"); 
	    		if(select) {
	    			stringBuffer.append("<td valign='top' align='center' class='tableRow'>Select</td>");
	    		}
			    for (int i = 1; i <= count; i++) {
		    		stringBuffer.append("<td id='" + i + "' class='tableRow' ondblclick='toggleWrap(this.id, " + totalNoOfRows + ")' nowrap='nowrap'>");
			    	stringBuffer.append(rsmd.getColumnName(i) + " [" + rsmd.getColumnTypeName(i).toLowerCase() + "]");
			    	stringBuffer.append("</td>");
			   	}		
		    	stringBuffer.append("</tr>");   
		    	
			    while(rst.next()) {
			    	if(z > rowsPerPage) {
			    		break;
			    	}
			    	stringBuffer.append("<tr valign='top' name='checkBox" + z + "' onmouseover='focusRow(this)' onmouseout='defocusRow(this)'>");
			    	/* 
			    	 * If we are seeing the content of the table.
			    	 * We need to have a select box.
			    	 */
			    	if(select) {
				    	stringBuffer.append("<td valign='top' class='tableRow' align='center' width='20px'>");
				    	stringBuffer.append("<input type='checkbox' id='selectedRow' name='selectedRow' value=" + rst.getString(1) + ">");
				    	stringBuffer.append("</td>");
			    	}
			    	
			    	/*
			    	 * Code for printing the Column Values
			    	 */
			    	for (int i = 1; i <= count; i++) {
				    	stringBuffer.append("<td id='column" + z + i + "' class='tableRow' ondblclick='toggleWrap(" + i + " , " + totalNoOfRows + ")' nowrap='nowrap' >");
				    	if(rsmd.getColumnTypeName(i) == "DATE" || rsmd.getColumnTypeName(i) == "DATETIME")
				    		stringBuffer.append(rst.getInt(i));
				    	else{
				    		String data = rst.getString(i);
				    		if(data != null && data.startsWith("<")){
				    			stringBuffer.append(parseXMLString(data));
				    		}
				    		else{
				    			stringBuffer.append(data);
				    		}		    	
				    	}
			        	stringBuffer.append("</td>");
				   	}		
			    	stringBuffer.append("</tr>");
			    	z++;
			    }
			    /*
			     * This will display a message when the table is without any rows.
			     */
			    if(!rst.first()) {
			    	stringBuffer.append("<tr>");
			    	stringBuffer.append("<td colspan=" + (count + 1) + " class='tableRow'><span style='color:red;'>The table is empty.</span></td>");
			    	stringBuffer.append("</tr>");
			    }
			    if(pageLinksRequired && totalNoOfPages > 1) {
			    	stringBuffer.append("<tr>");
			    	stringBuffer.append("<td class='tableRow' colspan='" + (count + 1) + "'>");
			    	stringBuffer.append("Pages: ");
			    	for(int i = 1; i <= totalNoOfPages; i++) {
			    		String pageNumber = "" + i;
			    		if(i == currentPage) {
			    			pageNumber = "<font color='red'>" + i + "</font>";
			    		}
			    		String href = "<a href='" + getUrlForBreadCrumbs() + i + "'>" + pageNumber + "</a>";
			    		stringBuffer.append(href + "&nbsp;&nbsp;");
			    	}
			    	stringBuffer.append("</td>");
			    	stringBuffer.append("</tr>");
			    }
			    /*
			     * To get the number of rows count.
			     */
			    if(rowCountRequired) {
			    	stringBuffer.append("<tr>");
			    	stringBuffer.append("<td class='tableRow' colspan='" + (count + 1) + "'>");
			    	stringBuffer.append("Total Row Count: " + totalNoOfRows);
			    	stringBuffer.append("&nbsp;&nbsp;&nbsp;");
			    	stringBuffer.append("Page Row Count: " + (z - 1));
			    	stringBuffer.append("</td>");
			    	stringBuffer.append("</tr>");
			    }
			} catch (SQLException ex) {
				throw new SQLException("SQLException occured while forming the paginated table: " + ex.getMessage());
			}
		}
		else {
			try {
				int noOfRows = getRowCount(rst);
			    int count = rsmd.getColumnCount(); 
			    
			    stringBuffer.append("<tr>"); 
			    for (int i = 1; i <= count; i++) {
		    		stringBuffer.append("<td id='" + i + "' class='tableRow' ondblclick='toggleWrap(this.id, " + noOfRows + ")' nowrap='nowrap'>");
			    	stringBuffer.append(rsmd.getColumnName(i) + " [" + rsmd.getColumnTypeName(i).toLowerCase() + "]");
			    	stringBuffer.append("</td>");
			   	}		
		    	stringBuffer.append("</tr>");   
		    	
		    	
		    	int z = 1;
			    while(rst.next()) {
			    	stringBuffer.append("<tr valign='top' onmouseover='focusRow(this)' onmouseout='defocusRow(this)'>");
			    	/*
			    	 * Code for printing the Column Values
			    	 */
			    	for (int i = 1; i <= count; i++) {
				    	stringBuffer.append("<td id='column" + z + i + "' class='tableRow' ondblclick='toggleWrap(" + i + " , " + noOfRows + ")' nowrap='nowrap' >");
				    	if(rsmd.getColumnTypeName(i) == "DATE" || rsmd.getColumnTypeName(i) == "DATETIME")
				    		stringBuffer.append(rst.getInt(i));
				    	else{
				    		String data = rst.getString(i);
				    		if(data != null && data.startsWith("<")){
				    			stringBuffer.append(parseXMLString(data));
				    		}
				    		else{
				    			stringBuffer.append(data);
				    		}		    	
				    	}
			        	stringBuffer.append("</td>");
				   	}		
			    	stringBuffer.append("</tr>");
			    	z++;
			    }
			    
			    /*
			     * This will display a message when the table is without any rows.
			     */
			    if(!rst.first()) {
			    	stringBuffer.append("<tr>");
			    	stringBuffer.append("<td colspan=" + (count + 1) + " class='tableRow'><span style='color:red;'>The table is empty.</span></td>");
			    	stringBuffer.append("</tr>");
			    }
			    
			    /*
			     * To get the number of rows count.
			     */
			    if(rowCountRequired) {
			    	stringBuffer.append("<tr>");
			    	stringBuffer.append("<td class='tableRow' colspan='" + (count + 1) + "'>");
			    	stringBuffer.append("Row Count: " + noOfRows);
			    	stringBuffer.append("</td>");
			    	stringBuffer.append("</tr>");
			    }
			} catch (SQLException ex) {
				throw new SQLException("SQLException occured while forming the paginated table: " + ex.getMessage());
			}
		}
		return stringBuffer;
	}	

	public int getRowCount(ResultSet rst) throws SQLException {
		int noOfRows = 0;
		try {
		    while(rst.next()) {
		    	noOfRows++;
			}
		    rst.beforeFirst();
		}
		catch(SQLException ex) {
			throw new SQLException("SQLException occured while forming the paginated table: " + ex.getMessage());
		}
		return noOfRows;
	}
	
	public StringBuffer parseXMLString(String data){
		StringBuffer stringBuffer = new StringBuffer();
		for(int j = 0; j < data.length(); j++){
			if(data.charAt(j) == '<'){
				stringBuffer.append("&#60;");
			}
			else if(data.charAt(j) == '?'){
				stringBuffer.append("&#63;");			    					
			}
			else if(data.charAt(j) == '!'){
				stringBuffer.append("&#33;");			    					
			}
			else if(data.charAt(j) == '"'){
				stringBuffer.append("&#34;");			    					
			}
			else if(data.charAt(j) == '>'){
				stringBuffer.append("&#62;");			    					
			}
			else if(data.charAt(j) == '/'){
				stringBuffer.append("&#47;");			    					
			}
			else{
				stringBuffer.append(data.charAt(j));
			}
		}
		return stringBuffer;
	}
	
	private String getUrlForBreadCrumbs() {
		String url = "";
		if(servletPath.length() > 0) {
			url = url + servletPath;	
		}
		if(queryString.length() > 0) {
			url = url + "?" + queryString + "&p=";
		}
		else {
			url = url + "?p=";
		}
		return url;
	}
}
